using Magiq.Databases.Delete;
using Magiq.Databases.Insert;
using Magiq.Databases.Query;
using Magiq.Databases.Update;
using Magiq.Delete;
using Magiq.Insert;
using Magiq.Query;
using Magiq.Support;
using Magiq.Update;

namespace Magiq.Databases
{
    public abstract class MagiqToDatabases : MagiqProvider
    {
        #region IMagiqProvider Members

        public override IDeleteStrategy GetDeleteStrategy<T>(IDelete<T> delete)
        {
            var databaseAdapter = GetDatabaseAdapterFrom(delete);
            return databaseAdapter == null ? null : new DatabaseDeleteStrategy<T>(databaseAdapter, delete);
        }

        public override IInsertStrategy GetInsertStrategy<TSource, TDestination, TNew>(
            IInsert<TSource, TDestination, TNew> insert)
        {
            var databaseAdapter = GetDatabaseAdapterFrom(insert);
            return databaseAdapter == null
                       ? null
                       : new DatabaseInsertStrategy<TSource, TDestination, TNew>(databaseAdapter, insert);
        }

        public override IInsertDestination<TNew> GetInsertDestination<TSource, TDestination, TNew>(
            IInsert<TSource, TDestination, TNew> insertDestinationDefinition)
        {
            var databaseAdapter = GetDatabaseAdapterFromDestination(insertDestinationDefinition);
            return databaseAdapter == null ? null : databaseAdapter.GetInsertDestination(insertDestinationDefinition);
        }

        public override IQueryStrategy<TChild> GetQueryStrategy<T, TChild>(QueryInfo<T, TChild> queryInfo)
        {
            var databaseAdapter = GetDatabaseAdapterFrom(queryInfo);
            return databaseAdapter == null ? null : new DatabaseQueryStrategy<T, TChild>(databaseAdapter, queryInfo);
        }

        public override MagiqProviderOrderStrategy OrderStrategy
        {
            get { return MagiqProviderOrderStrategy.QueryInfoInCollection; }
        }

        public override IUpdateStrategy GetUpdateStrategy<T>(IUpdate<T> update)
        {
            var databaseAdapter = GetDatabaseAdapterFrom(update);
            return databaseAdapter == null ? null : new DatabaseUpdateStrategy<T>(databaseAdapter, update);
        }

        #endregion

        protected abstract IOrmAdapter GetDatabaseAdapterFrom<T>(IUpdate<T> update);

        protected abstract IOrmAdapter GetDatabaseAdapterFromDestination<TSource, TDestination, TNew>(
            IInsert<TSource, TDestination, TNew> insert);

        protected abstract IOrmAdapter GetDatabaseAdapterFrom<T>(IDelete<T> delete);
        protected abstract IOrmAdapter GetDatabaseAdapterFrom<T, TChild>(QueryInfo<T, TChild> queryInfo);

        protected abstract IOrmAdapter GetDatabaseAdapterFrom<TSource, TDestination, TNew>(
            IInsert<TSource, TDestination, TNew> insert);
    }
}